package elasticsearch

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/pkg/errors"
	log "github.com/sirupsen/logrus"
	"io/ioutil"
	"net/http"
	"strings"
	"time"
	"xj.com/oos-naming-service/config"
	"xj.com/oos-naming-service/dto"
	"xj.com/oos-naming-service/error_handler"
	"xj.com/oos-naming-service/utils"
)

const (
	indexNamePrefix           = "meta-"
	timeFormat                = "20060102"
	queryMetaInfoJsonTemplate = `
{
    "size": 1,
    "query": {
        "term": {
            "id.keyword": "%s"
        }
    }
}
`
	contentJson = "application/json"
)

type ElasticsearchService struct{}

func New() *ElasticsearchService {

	resp, err := http.Get(config.Config.Es.Url)
	error_handler.ExitWenError(errors.WithMessage(err, "确定与ES建立连接时失败。ES地址："+config.Config.Es.Url))

	body, err := ioutil.ReadAll(resp.Body)
	error_handler.ExitWenError(errors.WithMessage(err, "读取ES返回的数据出错"))

	if config.Config.Log.Level >= log.DebugLevel {
		log.Debug("ES响应：\n", string(body))
	}

	return new(ElasticsearchService)
}

func (s *ElasticsearchService) WriteMetaInfo(info dto.MetaInfo) {
	requestJson, err := json.Marshal(info)
	error_handler.HttpPanicIfError(errors.WithStack(err))
	utils.GetRestRequest()
	resp, err := http.DefaultClient.Post(s.getIndexUrl(s.getIndexName(info.ObjectCreateTime)), contentJson, bytes.NewReader(requestJson))
	if resp != nil {
		defer resp.Body.Close()
	}
	error_handler.HttpPanicIfError(errors.WithStack(err))
}

func (s *ElasticsearchService) GetMetaInfo(objectId string) dto.MetaInfo {
	fullQueryJson := fmt.Sprintf(queryMetaInfoJsonTemplate, objectId)

	if config.Config.Log.Level >= log.DebugLevel {
		log.Debug("ES请求：\n", fullQueryJson)
	}

	resp, err := http.DefaultClient.Post(s.getSearchUrl(), contentJson, strings.NewReader(fullQueryJson))
	if resp != nil {
		defer resp.Body.Close()
	}
	error_handler.HttpPanicIfError(errors.WithStack(err))

	all, err := ioutil.ReadAll(resp.Body)

	if config.Config.Log.Level >= log.DebugLevel {
		log.Debug("ES请求：\n", string(all))
	}

	error_handler.HttpPanicIfError(errors.WithStack(err))

	esResp := dto.EsSearchResponse{}
	err = json.Unmarshal(all, &esResp)
	error_handler.HttpPanicIfError(errors.WithStack(err))
	//esResp.Hits无论如何都会返回
	if len(esResp.Hits.Hits) == 0 {
		error_handler.HttpPanicIfError(errors.New("未找到ID:" + objectId + "对应的元数据。"))
	}
	return esResp.Hits.Hits[0].MetaInfo
}

func (s *ElasticsearchService) getSearchUrl() string {
	return config.Config.Es.Url + "/" + indexNamePrefix + "*/_search"
}

func (s *ElasticsearchService) getIndexUrl(indexName string) string {
	return config.Config.Es.Url + "/" + indexNamePrefix + indexName + "/meta"
}

func (s *ElasticsearchService) getIndexName(dateTime time.Time) string {
	return dateTime.Format(timeFormat)
}
